/*
 * TMap Designer - A Thematic Map design software
 * Copyright (C) 2006 World Health Organization
 * http://www.who.int
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
package who.tmap.toolkit.shape.annotation.impl;

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.TexturePaint;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;

import who.tmap.bo.cd.CDProportionalSymbols;
import who.tmap.bo.cd.CDTypes;
import who.tmap.bo.cd.CartographicDisplay;
import who.tmap.services.TextureService;
import who.tmap.toolkit.impl.ShapeHelper;
import who.tmap.toolkit.shape.annotation.LegendShape;

public class LegendShapeImpl extends BaseTextMapShapeImpl implements LegendShape {

    private static Logger logger = Logger.getLogger(LegendShapeImpl.class);
    
	// Where to start writing the text for the samples
	private static final double LEGEND_SAMPLE_HGAP_FACTOR =1.5d;
	// Size factor of the sample
	private static final double SAMPLE_SIZE_FACTOR =1.15d;
	
	private static TextureService textureHelper =TextureService.getInstance();
	
	private CartographicDisplay cd;
	private String text;
	private boolean backgroundTransparent;

	private List<String> colorPatternLegend;
	private boolean colorPatternRoundRangesBoundaries;	
	private List<LegendSample> legendSamples;
	private boolean proportionalSymbolsRoundValues;
	
	private ShapeHelper shapeHelper =new ShapeHelper();
	
	private ColorPatternLegendShapeHelper cpHelper =new ColorPatternLegendShapeHelper( this );
	private ProportionalSymbolsLegendShapeHelper psHelper =new ProportionalSymbolsLegendShapeHelper( this );
	private PointLegendShapeHelper pointHelper =new PointLegendShapeHelper( this );
	
	public LegendShapeImpl() {
		super();
		setType( LEGEND );
		setPt( null );
	}	
	
	public TexturePaint getTexturePaint( int idx ) {
		return textureHelper.getTexturePaint()[ idx ];
	}

	public String getText() {
		return text;
	}

	public void setText(String text) {
		this.text = text;
	}		

	public boolean isBackgroundTransparent() {
		return backgroundTransparent;
	}

	public void setBackgroundTransparent(boolean backgroundTransparent) {
		this.backgroundTransparent = backgroundTransparent;
	}

	public CartographicDisplay getCartographicDisplay() {
		return cd;
	}

	public void setCartographicDisplay(CartographicDisplay cd) {
		this.cd = cd;
	}	
	
	public List<String> getColorPatternLegend() {
		return colorPatternLegend;
	}

	public void setColorPatternLegend(List<String> colorPatternLegend) {
		this.colorPatternLegend = colorPatternLegend;
	}		
	
	public boolean isColorPatternRoundRangesBoundaries() {
		return colorPatternRoundRangesBoundaries;
	}

	public void setColorPatternRoundRangesBoundaries(
			boolean colorPatternRoundRangesBoundaries) {
		this.colorPatternRoundRangesBoundaries = colorPatternRoundRangesBoundaries;
	}	

	public boolean isProportionalSymbolsRoundValues() {
		return proportionalSymbolsRoundValues;
	}

	public void setProportionalSymbolsRoundValues(
			boolean proportionalSymbolsRoundValues) {
		this.proportionalSymbolsRoundValues = proportionalSymbolsRoundValues;
	}	

	public List<LegendSample> getLegendSamples() {
		return legendSamples;
	}

	private TextRenderingHelper prepareLegend( Graphics2D g, Point2D legendTextPt) {
		TextRenderingHelper trh =null;
		
		legendSamples =new ArrayList<LegendSample>();
		
		switch( cd.getType() ) {
			case CDTypes.COLOR_PATTERN:
				trh =cpHelper.prepareLegend( g, legendTextPt, getScreenToMapFactor() );
				break;
				
			case CDTypes.POINT_BASIC:
			case CDTypes.POINT_DATA_DRIVEN_SIZE:
			case CDTypes.POINT_DATA_DRIVEN_SYMBOL:
			case CDTypes.POINT_DATA_DRIVEN_SYMBOL_AND_SIZE:
				trh =pointHelper.prepareLegend( g, legendTextPt, getScreenToMapFactor() );
				break;
				
			case CDTypes.PROPORTIONAL_SYMBOLS:
				trh =psHelper.prepareLegend( g, legendTextPt, getScreenToMapFactor() );
				break;
		}
		
		return trh;
	}	
	
	private TextRenderingHelper prepareTitle( Graphics2D g2 ) {
		TextRenderingHelper trh =new TextRenderingHelper( getScreenToMapFactor(), getZoomFactor() );
		
		trh.init( g2, fontName, fontStyle, fontSize );
		
		trh.prepareTextForRendering( g2, getText(), pt, TextRenderingHelper.NO_MARGINS );
		
		return trh;
	}
	
	private void renderLegendSamples( Graphics2D g, double width, double height ) {
		for( LegendSample sample : legendSamples ) {
			
			sample.draw( g, width, height, getScreenToMapFactor(), getZoomFactor() );
		}
	}
	
	public void draw(Graphics g) {
		Graphics2D g2 =(Graphics2D)g;
		
		TextRenderingHelper trhTitle =prepareTitle( g2 );
		
		bounds =trhTitle.getBounds();
		
		double x =pt.getX() + (trhTitle.getLineHeight() * LEGEND_SAMPLE_HGAP_FACTOR);
		double y =bounds.getMaxY() + trhTitle.getLeading() + trhTitle.getLineHeight();
		
		TextRenderingHelper trhLegend =prepareLegend( g2, new Point2D.Double( x, y ) );
		
		if ( trhLegend != null && trhLegend.getBounds() != null ) {
			bounds.add( trhLegend.getBounds() );
		}		
		
		// Apply to the bounds of the entire legend, not title only !!
		trhTitle.addMargins( bounds );
		if ( !backgroundTransparent ) {
			trhTitle.eraseBackground( g2, bounds, getBackgroundColor() );
		}
		
		trhTitle.renderText( g2, backgroundTransparent, getBackgroundColor() );
		
		if ( cd instanceof CDProportionalSymbols ) {
			psHelper.renderProportionalSymbols( g2, trhLegend );
		} else {
			if ( trhLegend != null ) {
				trhLegend.renderText( g2, backgroundTransparent, getBackgroundColor() );
			}
			renderLegendSamples( g2, trhTitle.getLineHeight() / SAMPLE_SIZE_FACTOR
								   , trhTitle.getLineHeight() / SAMPLE_SIZE_FACTOR  );
		}
		
		logger.debug( "legend bounds minX=" + bounds.getMinX() + ", minY=" + bounds.getMinY() 
						+ ", width=" + bounds.getWidth() + ", height=" + bounds.getHeight() );
		
		displaySelectionHandles( g );
	}
	
	public void moveShape(Point2D anchor, Point2D movingAnchor) {
		//super.moveShape( anchor, movingAnchor );
	    double offsetX =movingAnchor.getX() - anchor.getX();
	    double offsetY =movingAnchor.getY() - anchor.getY();
	    
		double origWidth =bounds.getWidth() / ( 1d + ( TextRenderingHelper.LEGEND_MARGIN * 2d ) );
		double origHeight =bounds.getHeight() / ( 1d + ( TextRenderingHelper.LEGEND_MARGIN * 2d ) );
		
		double widthMargin =( bounds.getWidth() - origWidth ) / 2d;
		double heightMargin =( bounds.getHeight() - origHeight ) / 2d;
		
	    pt.setLocation( pt.getX() + offsetX , pt.getY() + offsetY );	
		
		bounds.setFrame( //bounds.getMinX() - widthMargin, bounds.getMinY() - heightMargin
						 pt.getX() - Math.abs( widthMargin )
					   , pt.getY() - Math.abs( heightMargin )
					   , bounds.getWidth(), bounds.getHeight() );
		
		logger.debug( "legend moveShape bounds minX=" + bounds.getMinX() + ", minY=" + bounds.getMinY() 
					+ ", width=" + bounds.getWidth() + ", height=" + bounds.getHeight() );		
	}	

}
